/**
 * 
 */
package com.xpec.c4.game.time;

import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.service.module.schedule.LogOnJobObjectException;

/**
 * 定时器
 * 
 * @author lipeilin
 * @2011-4-28 下午02:56:14
 *
 */
public class JobSchedule extends ScheduledThreadPoolExecutor{
	
	private static final Log log = LogFactory.getLog(JobSchedule.class);

	@Override
	public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
		ScheduledFuture<?> task = null;
		try {
			task = super.schedule(wrapRunnable(command), delay, unit);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error("JobSchedule.schedule() fail.", e);
			}
		}

		return task;
	}

	@Override
	public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
		ScheduledFuture<?> task = null;
		try {
			task = super.scheduleAtFixedRate(wrapRunnable(command), initialDelay, period, unit);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error("JobSchedule.scheduleAtFixedRate() fail.", e);
			}
		}

		return task;
	}

	/**
	 * 將 runnable 物件導向自己多包一層的 runnable 物件, 目的是要抓出造成 runnable 物件停止執行的 exception
	 * 
	 * @param command
	 * @return
	 */
	private Runnable wrapRunnable(Runnable command) {
		Runnable runObj = null;
		try {
			runObj = new LogOnJobObjectException(command);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error("JobSchedule.wrapRunnable() fail.", e);
			}
		}

		return runObj;
	}

	/**
	 * @param corePoolSize
	 */
	public JobSchedule(int corePoolSize) {
		super(corePoolSize);
		setKeepAliveTime(10, TimeUnit.SECONDS);
		allowCoreThreadTimeOut(true);
		setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
	}

	@Override
	protected void afterExecute(Runnable r, Throwable t) {
		if(r instanceof RunnableScheduledFuture){
			RunnableScheduledFuture<?> task = (RunnableScheduledFuture<?>)r;
			if(task.isDone()){
				try {
					task.get();
				} catch (InterruptedException e) {
					//log.error(r,e);
				} catch (ExecutionException e) {
					log.error(r,e);
				} catch (CancellationException e) {
				}
				remove(r);
			}
		}
		if(t!=null){
			log.error(r,t);
		}
		super.afterExecute(r, t);
	}

}
